/**
 * Copyright (C) 2011 GreenSoft S.A.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *        http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ar.com.greensoft.neosystem.dao.jpa;

import java.io.Serializable;
import java.util.Collection;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;

import ar.com.greensoft.neosystem.dao.DaoException;


/**
 * Abstract JPA Data Access Object Pattern Implementation
 * @author Jorge E. Villaverde
 * @date 08/07/2011
 * @version 1.0.0
 */
public abstract class AbstractJpaDaoImpl<T, PK extends Serializable> 
	extends CommonJpaDaoImpl<T, PK> {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	// Constants ----------------------------------------------------------------------------------
	
	// Properties ---------------------------------------------------------------------------------
	
	// Dependencies -------------------------------------------------------------------------------
	
	// Methods ------------------------------------------------------------------------------------
		
	protected EntityManager getEntityManager(){
		return entityManager;
	}
				
	@Override
	public T findById(PK id) throws DaoException {
		if(logger.isTraceEnabled())
			logger.trace("Returning entity of type: " + getEntityClazz().getSimpleName() + "\twith id: " + id);
		return getEntityManager().find(getEntityClazz(), id);
	}	
			
	protected Collection<T> findByCriteria(CriteriaQuery<T> criteria) {
		TypedQuery<T> typedQuery = entityManager.createQuery(criteria);
		return typedQuery.getResultList();
	}	

	
	@Override
	public T findByName(String name) {
		if(logger.isTraceEnabled())
			logger.trace("Returning entity of type: " + getEntityClazz().getSimpleName() + "\twith name: " + name);
		entityManager.clear();
		TypedQuery<T> query = createFindByNameEntityTypedQuery();
		
		query.setParameter("name", name);
		
		return findSingleResult(query);
	}
	

	protected TypedQuery<T> createFindByNameEntityTypedQuery(){
		return getEntityManager().createNamedQuery(getFindByNameNamedQuery(), getEntityClazz());
	}
		
	protected T findSingleResult(TypedQuery<T> query){
		try {
			return query.getSingleResult();
		} catch (NoResultException e) {
		} catch (NonUniqueResultException e) {
		}
		return null;
	}
	
	protected Predicate appendAndPredicate(Predicate predicate, Predicate appendPred) {
		if(predicate == null){
			return appendPred;
		}
		return getEntityManager().getCriteriaBuilder().and(predicate, appendPred);
	}
		
	// Abstract Methods ---------------------------------------------------------------------------

	protected abstract String getFindByNameNamedQuery();
		
}